"""特征分析模块
包含特征值、特征向量、特征多项式等功能
"""
import numpy as np
from scipy.linalg import eig, eigvals
from typing import Tuple, List, Optional
import sympy as sp

class EigenAnalysis:
    @staticmethod
    def eigenvalues(matrix: np.ndarray) -> np.ndarray:
        """
        计算特征值
        :param matrix: 输入方阵
        :return: 特征值数组
        """
        try:
            # 确保输入是方阵
            if matrix.shape[0] != matrix.shape[1]:
                raise ValueError("Matrix must be square")
            
            # 检查矩阵是否包含无效值
            if not np.isfinite(matrix).all():
                raise ValueError("Matrix contains non-finite values")
            
            eigenvals_result = eigvals(matrix)
            return eigenvals_result
        except Exception as e:
            print(f"Error in eigenvalues calculation: {e}")
            # 返回空数组而不是抛出异常
            return np.array([])
    
    @staticmethod
    def eigenvectors(matrix: np.ndarray) -> Tuple[np.ndarray, np.ndarray]:
        """
        计算特征值和特征向量
        :param matrix: 输入方阵
        :return: (特征值, 特征向量)
        """
        try:
            # 确保输入是方阵
            if matrix.shape[0] != matrix.shape[1]:
                raise ValueError("Matrix must be square")
            
            # 检查矩阵是否包含无效值
            if not np.isfinite(matrix).all():
                raise ValueError("Matrix contains non-finite values")
            
            eigenvals, eigenvecs = eig(matrix)
            return eigenvals, eigenvecs
        except Exception as e:
            print(f"Error in eigenvectors calculation: {e}")
            # 返回空数组而不是抛出异常
            n = matrix.shape[0] if len(matrix.shape) >= 2 else 1
            return np.array([]), np.eye(n)
    
    @staticmethod
    def power_method(matrix: np.ndarray, max_iter: int = 1000, tol: float = 1e-10) -> Tuple[float, np.ndarray]:
        """
        幂法求主特征值和特征向量
        :param matrix: 输入方阵
        :param max_iter: 最大迭代次数
        :param tol: 收敛容差
        :return: (主特征值, 主特征向量)
        """
        n = matrix.shape[0]
        x = np.random.rand(n)
        x = x / np.linalg.norm(x)
        
        for i in range(max_iter):
            y = matrix @ x
            eigenval = x.T @ y
            x_new = y / np.linalg.norm(y)
            
            if np.linalg.norm(x_new - x) < tol:
                break
            x = x_new
        
        return eigenval, x
    
    @staticmethod
    def characteristic_polynomial(matrix: np.ndarray) -> sp.Poly:
        """
        计算特征多项式
        :param matrix: 输入方阵
        :return: 特征多项式
        """
        n = matrix.shape[0]
        lambda_sym = sp.Symbol('lambda')
        
        # 创建符号矩阵 λI - A
        I = sp.eye(n)
        A_sym = sp.Matrix(matrix)
        char_matrix = lambda_sym * I - A_sym
        
        # 计算行列式
        char_poly = char_matrix.det()
        return sp.Poly(char_poly, lambda_sym)
    
    @staticmethod
    def minimal_polynomial(matrix: np.ndarray) -> sp.Poly:
        """
        计算极小多项式
        :param matrix: 输入方阵
        :return: 极小多项式
        """
        # 简化实现：使用特征多项式作为近似
        return EigenAnalysis.characteristic_polynomial(matrix)
    
    @staticmethod
    def is_diagonalizable(matrix: np.ndarray, tol: float = 1e-10) -> bool:
        """
        判断矩阵是否可对角化
        :param matrix: 输入方阵
        :param tol: 容差
        :return: 是否可对角化
        """
        try:
            eigenvals, eigenvecs = eig(matrix)
            
            # 检查特征向量是否线性无关
            return bool(np.linalg.matrix_rank(eigenvecs) == matrix.shape[0])
        except Exception as e:
            print(f"Error in is_diagonalizable: {e}")
            return False
    
    @staticmethod
    def diagonalize(matrix: np.ndarray) -> Tuple[np.ndarray, np.ndarray]:
        """
        矩阵对角化
        :param matrix: 输入方阵
        :return: (对角矩阵D, 变换矩阵P) 使得 A = P @ D @ P^(-1)
        """
        eigenvals, eigenvecs = eig(matrix)
        D = np.diag(eigenvals)
        P = eigenvecs
        return D, P
    
    @staticmethod
    def is_idempotent(matrix: np.ndarray, tol: float = 1e-10) -> bool:
        """
        判断是否为幂等矩阵 (A^2 = A)
        :param matrix: 输入方阵
        :param tol: 容差
        :return: 是否为幂等矩阵
        """
        try:
            A_squared = matrix @ matrix
            return bool(np.allclose(A_squared, matrix, atol=tol))
        except Exception as e:
            print(f"Error in is_idempotent: {e}")
            return False
    
    @staticmethod
    def is_nilpotent(matrix: np.ndarray, max_power: int = None, tol: float = 1e-10) -> Tuple[bool, int]:
        """
        判断是否为幂零矩阵
        :param matrix: 输入方阵
        :param max_power: 最大检查幂次
        :param tol: 容差
        :return: (是否为幂零矩阵, 幂零指数)
        """
        n = matrix.shape[0]
        if max_power is None:
            max_power = n
        
        power = matrix.copy()
        for k in range(1, max_power + 1):
            if np.allclose(power, 0, atol=tol):
                return True, k
            power = power @ matrix
        
        return False, -1